(function() {
	function title_template(){
		var template = '<div class="el-gantt-title" :style="{\'width\': width + \'px\'}">' +
			'<div class="el-gantt-title-item" v-for="item in showColumns" :style="{\'width\': item.width + \'px\'}">' +
			'<slot name="ganttTitle" :title="item">{{item.name}}</slot>' + 
			'</div>' + 
			'</div>';
		return template;
	}
	var title_options = {
		name: "el-gantt-title",
		data: function() {
			return {
				width: 0,
				showColumns: [],
			};
		},
		props: {
			columns: {
				type: Array,
				required: true
			},
		},
		watch: {
			columns: function(){
				this.getShowColumns();
			}
		},
		methods: {
			getShowColumns: function(){
				var width = 0,num = 0,index = 0,showColumns = [];
				for (var i = 0; i < this.columns.length; i++) {
					var item = Object.assign({},this.columns[i]);
					if (item.width) width += item.width;
					else width += 100;
					
					if(num > 0){
						showColumns[index].width += item.width;
					} else {
						index++;
						showColumns.push(item);
					}
					if(item.colspan) {
						num = item.colspan;
					}
					num--;
				}
				this.width = width;
				this.showColumns = showColumns;
			}
		},
		mounted: function(){
			this.getShowColumns();
		},
		template: title_template(),
	}

	function column_template() {
		var template = '<div class="el-gantt-column">' +
			'<div class="el-gantt-lable" v-for="(item,index) in row.columns" :class="!hasChild && index == row.columns.length - 1 ? \'last-lable\' : \'\'" :style="columnCss(item)"><el-gantt-column-item :obj="item"></el-gantt-column-item></div>' +
			'<template v-if="hasChild">' +
			'<div class="el-gantt-children">' +
			'<el-gantt-column v-for="item in row.children" :row="item" :rowHeight="rowHeight"></el-gantt-column>' +
			'</div></template>' +
			'</div>';
		return template;
	}
	var column_options = {
		name: "el-gantt-column",
		data: function() {
			return {
			}
		},
		props: {
			row: {
				type: Object,
				required: true
			},
			rowHeight: Number
		},
		computed: {
			hasChild: function(){
				if(Array.isArray(this.row.children) && this.row.children.length > 0) return true;
				return false;
			}
		},
		methods: {
			columnCss: function(column){
				if(this.hasChild){
					return {
						width: column.width + 'px'
					};
				}
				return {
					width: column.width + 'px',
					height: this.rowHeight + 'px'
				}
			}
		},
		created:function(){
			const parent = this.$parent;
			if(parent.isGantt){
				this.$column = parent;
			} else {
				this.$column = parent.$column;
			}
		},
		template: column_template(),
		components: {
			"el-gantt-column-item": {
				name: "el-gantt-column-item",
				props: {
					obj: {
						type: Object,
						required: true
					}
				},
				render: function(createElement){
					var parent = this.$parent.$column;
					var row = this.obj;
					return parent.$scopedSlots.default ? parent.$scopedSlots.default(row) : createElement("div", {
		                class: "el-gantt_label",
		            }, row.text);
				},
			}
		},
	}

	function dayValue_template(){
		var template = '<div class="el-gantt-column-day">' + 
			'<template v-for="(item,index) in data"><template v-for="citem in item.values">' +
			'<div :class="setClass(item,citem)" @click.stop="itemClick(item,citem)" :style="getCss(citem,index)" :title="citem.showTitle">{{citem.showTitle}}</div>' +
			'</template></template>' +
			'</div>';
		return template;
	}
	var dayValue_options = {
		name: "el-gantt-column-day",
		data: function() {
			var top = 9,
				itemHeight = this.rowHeight - top * 2 - 1;
			return {
				data: [],
				itemHeight: itemHeight
			}
		},
		props: {
			source: {
				type: Array,
				required: true
			},
			filterTime: String, //时间查询
			timeColumn: String, //时间集合字段配置
			swatchMode: Number,//0年模式 1月模式
			rowHeight: Number,//行高
			dateWidth: Number,//日期每个日期块的宽度
		},
		watch: {
			source: {
				deep: true,
				handler: function(){
					this.data = this.dataFormat(JSON.parse(JSON.stringify(this.source)));
				}
			},
			swatchMode: function(){
				this.data = this.dataFormat(JSON.parse(JSON.stringify(this.source)));
			}
		},
		methods: {
			//点击事件绑定
			itemClick: function(row,item){
				this.$emit("itemClick",{
					row: row,
					item: item
				});
			},
			//设置样式
			setClass: function(row,item){
				var result = "dateItem";
				this.$emit("setClass", {
					row: row,
					item: item
				}, function(className){
					if(className) result = className;
				});
				return result;
			},
			//数据格式化
			dataFormat: function(data){
				var that = this;
				data.forEach(function(item,index){
					item.values = item[that.timeColumn];
					if(!item.values || !Array.isArray(item.values)) item.values = [];
					var values = [];
					for(var i = 0; i < item.values.length; i++){
						var cItem = item.values[i],boo = true;
						values.forEach(function(obj){
							var d = that.difference(obj.from, cItem.from),
								d1 = that.difference(obj.to, cItem.to),
								d2 = that.difference(obj.from, cItem.to),
								d3 = that.difference(obj.to, cItem.from);
							if((d <=  0 && d3 >= 0) || (d1 >= 0 && d2 <= 0)){
								if(obj.showTitle) obj.showTitle += ",";
								obj.showTitle += cItem.showTitle;
								if(d > 0) obj.from = cItem.from;
								if(d1 < 0) obj.to = cItem.to;
								boo = false;
								return;
							}
						});
						if(boo){
							values.push(cItem);
						}
					}
					item.values = values;
				});
				return data;
			},
			//设置每天任务的坐标与大小
			getCss: function(obj,index){
				var top = index * this.rowHeight + 9,
					width = this.difference(obj.to,obj.from) + 1,
					left = this.difference(obj.from, this.filterTime),
					end = this.difference(obj.to, this.filterTime);
				if(left < 0){
					if(this.swatchMode === 0 && end > 24) {
						width = 24;
					} else if(this.swatchMode === 1 && end > 30){
						width = 30;
					} else {
						width += left;
					}
					left = 0;
				} else {
					if(this.swatchMode === 0 && end > 24) {
						width = 24 - left;
					} else if(this.swatchMode === 1 && end > 30){
						width = 30 - left;
					}
				}
				return {
					top: top + 'px',
					height: this.itemHeight + 'px',
					width: width * this.dateWidth + "px",
					left: left * this.dateWidth + "px"
				};
			},
			//计算
			difference: function(date1,date2){
				date1 = new Date(date1);
				date2 = new Date(date2);
				if(this.swatchMode === 0) {
					var year = date1.getFullYear() - date2.getFullYear();
					var month = date1.getMonth() - date2.getMonth();
					return year * 12 + month;
				} else {
					var difference = date1.getTime() - date2.getTime();//时间差的毫秒数
					return Math.ceil(difference / 1000 / 60 / 60 / 24);
				}
			},
		},
		mounted: function(){
			this.data = this.dataFormat(JSON.parse(JSON.stringify(this.source)));
		},
		template: dayValue_template(),
	}

	function template() {
		var template = '<div class="el-gantt">' +
			'<div class="el-gantt-head" v-if="hasHead"><div class="el-gantt-head-title">{{title}}</div>' +
			'<div class="el-gantt-tool">' +
			'<el-date-picker v-model="filterTime" align="right" :tyoe="swatchMode == 0 ? \'month\' : \'date\'" placeholder="选择日期"></el-date-picker>' +
			'<div class="el-gantt-mode" :class="isToday ? \'active\' : \'\'" @click="getNowDate">{{swatchMode == 0 ? \'今年\' : \'今天\'}}</div>' +
			'<div class="el-gantt-mode" :class="swatchMode == 0 ? \'active\' : \'\'" @click="swatchMode = 0">年</div>' +
			'<div class="el-gantt-mode" :class="swatchMode == 1 ? \'active\' : \'\'" @click="swatchMode = 1">月</div>' +
			'</div></div>' +
			'<div class="el-gantt-body">' +
			'<div class="el-gantt-left">' +
			'<div class="el-gantt-top"><el-gantt-title :columns="columns"></el-gantt-title></div>' +
			'<div class="el-gantt-content" ref="columnRows" @mousewheel.stop="mousewheel"><el-gantt-column v-for="(item, index) in source" :rowHeight="rowHeight" :row="item"></el-gantt-column></div>' +
			'</div>' +
			'<div class="el-gantt-right">' +
			'<div class="el-gantt-top" ref="dateHead"><div class="el-gantt-year" v-for="item in dateArray" :key="item.name"><div v-if="hasYear">{{item.name}}</div>' +
			'<div class="el-gantt-day-list"><div class="el-gantt-day" v-for="citem in item.children" :key="item.name + citem">{{citem}}</div></div>' +
			'</div></div>' +
			'<div class="el-gantt-content" ref="dateRows" @mousewheel.stop="mousewheel">' +
			'<el-gantt-column-day :style="\'height:\' + (rowHeight * data.length) + \'px;\' + \'width:\' + (dateWidth * (swatchMode === 1 ? 30 : 24)) + \'px\'" :source="sortData" :filterTime="filterTime" :swatchMode="swatchMode" :rowHeight="rowHeight" :timeColumn="timeColumn" :dateWidth="dateWidth" @itemClick="itemClick" @setClass="setClass"></el-gantt-column-day>' +
			'<div ref="scrollX" class="el-gantt-scroll el-gantt-scrollX" @scroll.passive="scrollX"><div :style="\'width:\' + (dateWidth * (swatchMode === 1 ? 30 : 24)) + \'px\'"></div></div>' +
			'<div ref="scrollY" class="el-gantt-scroll el-gantt-scrollY" @scroll.passive="scrollY"><div :style="\'height:\' + (rowHeight * data.length) + \'px\'"></div></div>' +
			'</div>' +
			'</div></div>' +
			'</div>';
		return template;
	}

	var options = {
		name: "el-gantt",
		data: function() {
			return {
				tableWidth: 0,
				filterTime: "", //时间查询
				swatchMode: 1, //0年模式 1月模式
				dateArray: [], //获取日历
				sortData: [],//排序后数据
				source: [], //处理后数据
				ctrlKeyDonw: false,//是否按下ctrl
			};
		},
		props: {
			title: String,//标题
			columns: {
				type: Array,
				required: true
			},//列信息
			data: {
				type: Array,
				required: true,
				default: function() {
					return [];
				}
			},//数据
			timeColumn: {
				type: String,
				default: "values"
			},//时间集合字段配置
			rowHeight: {
				type: Number,
				default: 41
			},//行高
			dateWidth: {
				type: Number,
				default: 62
			},//日期宽度
			hasYear: {
				type: Boolean,
				default: true
			},//是否显示年
			hasHead: {
				type: Boolean,
				default: true
			},//是否显示头部
			readonly: Boolean//是否只读
		},
		watch: {
			filterTime: function() {
				this.getDateArray();
			},
			swatchMode: function() {
				this.getDateArray();
				var scrollX = document.getElementsByClassName("el-gantt-scrollX")[0],
					scrollY = document.getElementsByClassName("el-gantt-scrollY")[0];
				if(scrollX) scrollX.scrollLeft = 0;
				if(scrollY) scrollY.scrollTop = 0;
			},
			data: function(){
				this.getSource();
			},
		},
		mounted:function(){
			this.getNowDate();
			this.getSource();
			var that = this;
			window.addEventListener("keydown",function(e){
				if(e.ctrlKey) {
					e.preventDefault();
					e.stopPropagation();
					that.ctrlKeyDonw = true;
				}
			})
			window.addEventListener("keyup",function(e){
				that.ctrlKeyDonw = false;
			});
			window.addEventListener('mousewheel', function(event){
				if (event.ctrlKey === true || event.metaKey) {
					  event.preventDefault();
				}
			},{ passive: false});
			
			//firefox
			window.addEventListener('DOMMouseScroll', function(event){
				if (event.ctrlKey === true || event.metaKey) {
					event.preventDefault();
				}
			},{ passive: false});
		},
		computed:{
			//是否今天
			isToday: function(){
				var time = new Date(this.filterTime);
				var now = new Date();
				return time.getFullYear() === now.getFullYear() && time.getMonth() === now.getMonth() && time.getDate() === now.getDate();
			},
		},
		methods: {
			//滚轮事件
			mousewheel: function(e){
				e.preventDefault();
				var deltaY = e.deltaY;
				if(this.ctrlKeyDonw){
					var scrollBar = document.getElementsByClassName("el-gantt-scrollX")[0];
					var scrollLeft = scrollBar.scrollLeft;
					var contentW = this.dateWidth * (this.swatchMode === 1 ? 30 : 24);
					if(deltaY > 0) {
						scrollLeft += 20;
						if(scrollLeft >= contentW - scrollBar.clientWidth) scrollLeft = contentW - scrollBar.clientWidth;
					} else {
						scrollLeft -= 20;
						if(scrollLeft <= 0) scrollLeft = 0;
					}
					scrollBar.scrollLeft = scrollLeft;
				} else {
					var scrollBar = document.getElementsByClassName("el-gantt-scrollY")[0];
					var scrollTop = scrollBar.scrollTop;
					var contentH = this.rowHeight * this.data.length;
					if(deltaY > 0) {
						scrollTop += 10;
						if(scrollTop >= contentH - scrollBar.clientHeight) scrollTop = contentH - scrollBar.clientHeight;
					} else {
						scrollTop -= 10;
						if(scrollTop <= 0) scrollTop = 0;
					}
					scrollBar.scrollTop = scrollTop;
				}
			},
			//左右滚动
			scrollX: function(e){
				this.$refs.dateHead.scrollLeft = e.target.scrollLeft;
				this.$refs.dateRows.scrollLeft = e.target.scrollLeft;
				this.$refs.scrollX.style.right = -e.target.scrollLeft + "px";
				this.$refs.scrollY.style.right = -e.target.scrollLeft + "px";
			},
			//上下滚动
			scrollY: function(e){
				this.$refs.columnRows.scrollTop = e.target.scrollTop;
				this.$refs.dateRows.scrollTop = e.target.scrollTop;
				this.$refs.scrollX.style.bottom = -e.target.scrollTop + "px";
				this.$refs.scrollY.style.bottom = -e.target.scrollTop + "px";
			},
			//点击事件绑定
			itemClick: function(params){
				this.$emit("itemClick",params);
			},
			//设置样式
			setClass: function(params){
				var result = null;
				this.$emit("setClass", params, function(className){
					result = className;
				});
				return result;
			},
			//今天或今年的快捷按钮
			getNowDate: function() {
				var date = new Date();
				this.filterTime = date.getFullYear() + "-" + (date.getMonth() + 1) + "-" + date.getDate();
			},
			//获取右侧时间轴
			getDateArray: function() {
				var date = new Date(this.filterTime),
					year = date.getFullYear(),
					month = date.getMonth() + 1,
					day = date.getDate(),
					index = 0,
					dateArray = [];
				if (this.swatchMode === 1) { //月视图
					dateArray.push({
						name: year + '-' + month,
						children: [day]
					})
					for (var i = 0; i < 29; i++) {
						date = new Date(date.getTime() + 3600 * 1000 * 24);
						var name = date.getFullYear() + '-' + (date.getMonth() + 1);
						if (dateArray[index].name != name) {
							dateArray.push({
								name: name,
								children: []
							});
							index++;
						}
						dateArray[index].children.push(date.getDate());
					}

				} else if (this.swatchMode === 0) { //年视图
					dateArray.push({
						name: year + '年',
						children: []
					})
					for (var i = 0; i < 24; i++) {
						if (month > 12) {
							month = 1;
							year++;
							dateArray.push({
								name: year + '年',
								children: []
							});
							index++;
						}
						dateArray[index].children.push(month + "月");
						month++;
					}
				}
				this.dateArray = dateArray;
			},
			//获取数据
			getSource: function(){
				var data = JSON.parse(JSON.stringify(this.data));
				this.source = this.formatData(data);
			},
			//数据进行处理
			formatData: function(sourceData){
				var that = this,sortData = [];
				//对数据进行递归分组
				function groupData(data,index){
					var keyData = {},result = [],startIndex = index;
					data.forEach(function(obj){
						var groupKey = [],columns = [],hasGroup = false;
						for(var i = startIndex; i < that.columns.length; i++){
							var column = that.columns[i];
							groupKey.push(obj[column.valueName]);
							columns.push({
								text: obj[column.columnName],
								value: obj[column.valueName],
								columnName: column.columnName,
								valueName: column.valueName,
								width: column.width,
							})
							if(column.hasGroup){
								groupKey = groupKey.join("-");
								if(!keyData[groupKey]) {
									keyData[groupKey] = {
										columns: columns,
										children: []
									};
								}
								keyData[groupKey].children.push(obj);
								hasGroup = true;
								index = i + 1;
								break;
							}
						}
						if(!hasGroup) {
							sortData.push(obj);
							result.push({
								columns: columns,
								children: []
							})
							return;
						}
					});
					for(var key in keyData) {
						result.push({
							columns: keyData[key].columns,
							children: groupData(keyData[key].children, index)
						})
					}
					return result;
				}
				var source = groupData(sourceData, 0);
				this.sortData = sortData;
				return source;
			},
			select: function(item){
				this.$emit('select',item);
			}
		},
		created: function(){
			this.isGantt = true;
		},
		template: template(),
		components: {
			"el-gantt-column": column_options,
			"el-gantt-title": title_options,
			"el-gantt-column-day": dayValue_options
		},
	}

	if (Vue) Vue.component("el-gantt", options);
})();
